package esrc.c9cf;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;


// http://www.glenmccl.com/tip_038.htm
// Sizeof For Java(tm)
// (c) Glen McCluskey & Associates LLC
// Retrieved May 10, 2012
public class SizeOf {
    
    private static final int SZ_REF = 4;

    public static int sizeof(boolean b)
    {
            return 1;
    }

    public static int sizeof(byte b)
    {
            return 1;
    }

    public static int sizeof(char c)
    {
            return 2;
    }

    public static int sizeof(short s)
    {
            return 2;
    }

    public static int sizeof(int i)
    {
            return 4;
    }

    public static int sizeof(long l)
    {
            return 8;
    }

    public static int sizeof(float f)
    {
            return 4;
    }

    public static int sizeof(double d)
    {
            return 8;
    }

    private static int size_inst(Class c)
    {
            Field flds[] = c.getDeclaredFields();
            int sz = 0;

            for (int i = 0; i < flds.length; i++) {
                    Field f = flds[i];
                    if (!c.isInterface() &&
                        (f.getModifiers() & Modifier.STATIC) != 0)
                            continue;
                    sz += size_prim(f.getType());
            }

            if (c.getSuperclass() != null)
                    sz += size_inst(c.getSuperclass());

            Class cv[] = c.getInterfaces();
            for (int i = 0; i < cv.length; i++)
                    sz += size_inst(cv[i]);

            return sz;
    }

    private static int size_prim(Class t)
    { 
            if (t == Boolean.TYPE)
                    return 1;
            else if (t == Byte.TYPE)
                    return 1;
            else if (t == Character.TYPE)
                    return 2;
            else if (t == Short.TYPE)
                    return 2;
            else if (t == Integer.TYPE)
                    return 4;
            else if (t == Long.TYPE)
                    return 8;
            else if (t == Float.TYPE)
                    return 4;
            else if (t == Double.TYPE)
                    return 8;
            else if (t == Void.TYPE)
                    return 0;
            else
                    return SZ_REF;
    }

    private static int size_arr(Object obj, Class c)
    {
            Class ct = c.getComponentType();
            int len = Array.getLength(obj);

            if (ct.isPrimitive()) {
                    return len * size_prim(ct);
            }
            else {
                    int sz = 0;
                    for (int i = 0; i < len; i++) {
                            sz += SZ_REF;
                            Object obj2 = Array.get(obj, i);
                            if (obj2 == null)
                                    continue;
                            Class c2 = obj2.getClass();
                            if (!c2.isArray())
                                    continue;
                            sz += size_arr(obj2, c2);
                    }
                    return sz;
            }
    }

    public static int sizeof(Object obj)
    {
            if (obj == null)
                    return 0;

            Class c = obj.getClass();

            if (c.isArray())
                    return size_arr(obj, c);
            else
                    return size_inst(c);
    }

    private static void err(String s)
    {
            System.err.println("*** " + s + " ***");
    }

    /*
    private static void test()
    {
            if (sizeof(null) != 0)
                    err("null");

            if (sizeof(true) != 1)
                    err("boolean");
            if (sizeof((byte)37) != 1)
                    err("byte");
            if (sizeof('x') != 2)
                    err("char");
            if (sizeof((short)37) != 2)
                    err("short");
            if (sizeof(37) != 4)
                    err("int");
            if (sizeof(37L) != 8)
                    err("long");
            if (sizeof(37.0f) != 4)
                    err("float");
            if (sizeof(37.0) != 8)
                    err("double");

            if (sizeof(new boolean[0]) != 0)
                    err("boolean[0]");
            if (sizeof(new byte[10]) != 10)
                    err("byte[10]"); 
            if (sizeof(new char[10][10]) != 200 + 10 * SZ_REF)
                    err("char[10][10]");
            if (sizeof(new short[10][11][12]) != 2640 +
                120 * SZ_REF)
                    err("short[10][11][12]");
            if (sizeof(new int[0][10]) != 0)
                    err("int[0][10]");

            if (sizeof(new String[100]) != 100 * SZ_REF)
                    err("String[100]");
            if (sizeof(new String[10][10]) != 110 * SZ_REF)
                    err("String[10][10]");

            Object ov[] = new Object[3];
            ov[0] = new byte[10];
            ov[2] = new double[10];
            if (sizeof(ov) != 90 + 3 * SZ_REF)
                    err("Object[3]");

            String sv[] = new String[10];
            for (int i = 0; i < 10; i++)
                    sv[i] = new String();
            if (sizeof(sv) != 10 * SZ_REF)
                    err("String[10]");

            if (sizeof(new Object()) != 0)
                    err("Object");
            if (sizeof(new Integer(37)) != 4)
                    err("Integer(37)");

            if (sizeof(new test_Class1()) != 5 + SZ_REF)
                    err("test_Class1");
            if (sizeof(new test_Class2()) != 8 + 2 * SZ_REF)
                    err("test_Class2");
            if (sizeof(new test_Class3()) != 19 + 2 * SZ_REF)
                    err("test_Class3");

            if (sizeof(new test_Class7()) != 13 + SZ_REF)
                    err("test_Class7");
    }

    public static void main(String args[])
    {
            test();
    }
    */
}
